'''
    run.py

        The 'run.py' module contains seven classe named 'grad_gui',
        'profile_maker', 'add_class_dialog', 'edit_class_dialog', 
        'edit_grade_dialog', 'cannot_remove_alert' and 'get_file'.
        These classes contain all the GUI code of the system. This
        module is also used to start and run the GRAD9001 application

        grad_gui

            Class 'grad_gui' is the system's GUI. It renders all
            the buttons, images and text to the user.

        profile_maker

            The 'profile_maker' class allows a new user to create
            a profile in the system

        add_class_dialog

            The 'add_class_dialog' allows the student to view a
            particular class' relevant information

        edit_class_dialog

            The 'edit_class_dialog' allows the student to change a
            particular course's information such as its grade or 
            removing it from the plan

        edit_grade_dialog

            The class 'edit_grade_dialog' allows the student to
            input a grade they received in a particular course

        cannot_remove_alert

            The class 'cannot_remove_alert' creates and displays
            an alert to the student when a particular course cannot
            be removed from their plan

        get_file

            The class 'get_file' lets the user choose a file,
            that he/she previously saved, for loading
'''

#!/usr/bin/env python
gladefile = "grad_app.glade"
from grad_app import *
import webbrowser
import report_gen
import sys
import filter
import pickle

try:
    import pygtk
    pygtk.require("2.0");
except:
    pass
try:
    import gtk
    import gtk.glade
except:
    print "Unable to load gtk. Shutting down..."
    sys.exit(1)
    
    
OK_RESPONSE = 1
CANCEL = 0
CHANGE_GRADE = 1
REMOVE_COURSE = 2
FALL = 0
WINTER = 1
SPRING = 2
SUMMER = 3
SEMESTERS = 4
SEASONS = [FALL, WINTER, SPRING, SUMMER]
GRADES = ['A', 'B', 'C', 'D', 'F', 'W', 'I', 'N/A']
SEASON_NAMES = ["Fall", "Winter", "Spring", "Summer"]

MAJOR_NAMES = ['All', 'Arts And Humanities', 'Biology', 'Chemistry', 
                'Computer Science', 'Culture', 'Management', 
                'Economics', 'English', 'Geography', 'Information Systems',
                'Foreign Language', 'Math', 'Physical Education', 
                'Physics', 'Science', 'Social Science', 'Statistics', 'All']
GEP_NAMES = ['All', 'Arts And Humanities', 'Culture', 'English', 
               'Foreign Language', 'Math', 'Physical Education',
               'Science', 'Social Science', 'Writing Intensive', 'All']

'''
    grad_gui

    Class 'grad_gui' is the system's GUI. It renders all
    the buttons, images and text to the user.
'''
class grad_gui:

    '''
        __init__()

        Initializes the system with the GUI and all
        other relevant information
    '''
    def __init__(self):

        self.gladefile = gladefile
        self.greeting_window = gtk.glade.XML(self.gladefile, "welcome_box") 
        dic = {"on_new_profile_activate" : self.on_new_profile_activate,
               "on_load_profile_clicked" : self.load_profile,
               "on_delete": self.delete_event,
               "on_destroy": self.destroy,
               "on_cancel_clicked": self.destroy}
        self.greeting_window.signal_autoconnect(dic)
    
    '''
        delete_event()

        **description here**
    '''
    def delete_event(self, widget, event, data=None):
        return False

    '''
        destroy()

        Closes the application
    '''
    def destroy(self, widget, data=None):
        gtk.main_quit()


    '''
        save_file()

        Saves the student's graduation plan
    '''
    def save_file(self, widget):
        if(self.app.save_name == None):
            response = get_file().run()
            if(response[0] == OK_RESPONSE):
                self.app.save_name = response[1]
                save_file = open(response[1], "w")            
                pickle.dump(self.app, save_file)
                save_file.close()
            else:
                return
        else:
            save_file = open(self.app.save_name, 'w')
            pickle.dump(self.app, save_file)
            save_file.close()

    def save_as(self, widget):
        response = get_file().run()
        if(response[0] == OK_RESPONSE):
            self.app.save_name = response[1]
            save_file = open(response[1], "w")            
            pickle.dump(self.app, save_file)
            save_file.close()
        else:
            return


    '''
        load_profile()

        Loads a student's profile
    '''
    def load_profile(self, widget):
        filechooser = get_file()
        response = filechooser.run()
        
        if(response[0] == OK_RESPONSE):
            load_file = open(response[1])
            self.app = pickle.load(load_file)
            load_file.close()

            # figure out where we are in the application
            try:
                # if we've already set up a main window, make a new one
                if(self.gui != None):
                    self.num_years = self.app.years
                    self.gui.get_widget("main_window").hide()
                    self.launch_app()
                    self.update_displays()
            except(AttributeError):
                # we are at the welcome screen, hide it and launch
                self.num_years = self.app.years
                self.greeting_window.get_widget("welcome_box").hide()
                self.launch_app()
                self.update_displays()
        else:
            return
        
    '''
        on_new_profile_activate()

        Allows a student o make a new profile
    '''        
    def on_new_profile_activate(self, widget):
        greeting_window = self.greeting_window.get_widget("welcome_box")
        greeting_window.hide()
        self.num_years = 4
        self.get_student_info()
 
    '''
        get_student_info()

        Takes the new student's starting information
    '''
    def get_student_info(self):
        student_dialog = profile_maker()
        result, name, major, minor = student_dialog.run()
        self.app = app(name, major, minor)
        self.launch_app()

    def edit_profile(self, widget):
        student_dialog = profile_maker()
        result, name, major, minor = student_dialog.run()
        stdnt = self.app.get_student()
        stdnt.name = name
        stdnt.major = major
        stdnt.minor = minor
        
    def start_anew(self, widget):
        self.gui.get_widget("main_window").hide()
        self.on_new_profile_activate(widget)


    '''
        launch_app()

        Launches the application
    '''
    def launch_app(self):

        self.gui = gtk.glade.XML(self.gladefile, "main_window")

        dic = {"on_filter_clicked" : self.filter_clicked
               , "on_filter_view_row_activated": self.filter_row_clicked
               , "on_save_button_clicked":self.save_file
               , "on_load_button_clicked": self.load_profile
               , "on_dars_activate": self.show_dars
               , "on_transcript_activate": self.show_transcript
               , "on_delete": self.delete_event
               , "on_destroy": self.destroy
               , "on_edit_profile_clicked": self.edit_profile
               , "on_help_activate": self.show_help
               , "on_quit_activate": self.destroy
               , "on_new_activate": self.start_anew
               , "on_open_activate": self.load_profile
               , "on_save_activate": self.save_file
               , "on_show_all_clicked":self.show_all
               , "on_save_as_activate": self.save_as}
        
        self.gui.signal_autoconnect(dic)
        
        self.course_view = self.gui.get_widget("filter_view")
        
        self.year_book = self.gui.get_widget("course_year_view")
        
        self.geps = self.gui.get_widget("gep_box")
        self.major = self.gui.get_widget("major_box")
        self.untaken = self.gui.get_widget("untaken")
        self.can_take = self.gui.get_widget("can_take")
        self.searchbox = self.gui.get_widget("search_box")
        self.courseList = gtk.ListStore(str)
        self.course_view.append_column(self.make_column("Courses"))
        self.course_view.set_model(self.courseList)   
        self.my_courses = []
        self.notebook_setup()

    '''
        show_dars()

        Generates and displays the student's
        Degree Audit
    '''
    def show_dars(self, widget):
        file = 'dars_temp.html'
        report_gen.export_dars(self.app.get_student(), file)
        webbrowser.open_new(file)
        
    def show_help(self, widget):
        webbrowser.open_new("help.html")


    '''
        show_transcript()

        Generates and displays the student's
        Unofficial Transcript
    '''  
    def show_transcript(self, widget):
        file = 'trans_temp.html'
        report_gen.export_transcript(self.app.get_student(), file)
        webbrowser.open_new(file)
        
    '''
        make_column()

        **description here**
    '''        
    def make_column(self, name):
        column = gtk.TreeViewColumn(name, gtk.CellRendererText(), text=0)
        column.set_resizable(True)
        column.set_sort_column_id(0)
        return column
    

    def show_all(self, widget):
        year = self.notebook.get_current_page()
        self.my_courses = self.app.get_courses(['All', 'All', '', False, False], year)
        self.update_displays()


    '''
        filter_clicked()

        Checks if the filter button has been clicked
    '''
    def filter_clicked(self, widget):
        year = self.notebook.get_current_page()
        self.my_courses = self.app.get_courses(self.get_search_options(), year)
        self.update_displays()

    '''
        filter_row_clicked()

        **description here**
    '''
    def filter_row_clicked(self, widget):
        
        model, path  =  self.course_view.get_selection().get_selected()
        try:
            course       = model[path][0].split('\t')[0]
            current_year = self.notebook.get_current_page()
            description, semesters = self.app.get_course_info(course, current_year)
            course_dialog = add_class_dialog()
            result, semester = course_dialog.run(description, semesters)
            if (result == OK_RESPONSE):
                self.app.add_course(course, SEMESTERS * current_year + semester)
            self.update_displays()
        except(TypeError):
             pass
 
    '''
        get_search_options()

        Returns the search options of the course database
    '''       
    def get_search_options(self):

        gep             = self.geps.get_active()
        major           = self.major.get_active()
        search          = self.searchbox.get_text()
        untaken         = self.untaken.get_active()
        can_take        = self.can_take.get_active()
        
        gep_name = GEP_NAMES[gep]
        major_name = MAJOR_NAMES[major]
       
        return [gep_name, major_name, search, untaken, can_take]
    
    '''
        add_year()

        Adds another year to the student's plan
    '''
    def add_year(self, widget):
        
        self.make_year(self.num_years)
        self.num_years += 1
        self.notebook.show_all()
        self.app.years = self.num_years
           
    '''
        add_semester()

        Adds a semester to a new year
    ''' 
    def add_semester(self, semester):
        new_view = gtk.TreeView()
        season = semester % SEMESTERS
        new_view.append_column(self.make_column(SEASON_NAMES[season]))
        new_list = gtk.ListStore(str)
        new_view.set_model(new_list)
        new_view.connect("row_activated", self.edit_course)
        self.semester_views.append(new_view)
        self.semester_lists.append(new_list)
        
    '''
        make_year()

        Displays all the years in the student's plan
    '''
    def make_year(self, year):
        for i in range(4):
            self.add_semester(i)
        yearnum = year + 1
        name = gtk.Label("Year " + str(yearnum))
        hbox = gtk.HBox()
        for j in range(SEMESTERS):
            hbox.add(self.semester_views[year * SEMESTERS + j])
        self.notebook.insert_page(hbox, tab_label = name, position = year)
        
    '''
        notebook_setup()

        Sets up the yearly view of the plan
    '''
    def notebook_setup(self):
        self.semester_views = []
        self.semester_lists = []
        self.notebook = self.gui.get_widget("course_year_view")
        for i in range(self.num_years):
            self.make_year(i)
        self.add_page_button = gtk.Button(label = "+")
        self.add_page_button.connect("clicked", self.add_year)
        self.notebook.append_page(self.add_page_button, self.add_page_button)
        self.notebook.show_all()
   
    '''
        edit_course()

        Allows the user to edit a course by changing
        its grade or removing it
    '''     
    def edit_course(self, widget, blah,blh):

        model, path  =  widget.get_selection().get_selected()
        course       = model[path][0].split('\t')[0]
        semester = self.semester_views.index(widget)

        sel_course = None
        for c in self.app.student_user._courses._courses:
            if c.is_named(course):
                sel_course = c

        
        current_year = self.notebook.get_current_page()
        description, semesters = self.app.get_student_course_info(course, current_year)
        course_dialog = edit_class_dialog()
        result = course_dialog.run(description)
        if result == CHANGE_GRADE:
            result, grade = edit_grade_dialog().run(description)
            grade = GRADES[grade]
            if result != CANCEL:
                self.app.change_grade(course, semester, grade)
        if result == REMOVE_COURSE:
            if self.app.can_remove_course(sel_course, semester):
                self.app.remove_course(sel_course, semester)
            else:
                cannot_remove_alert().run()
                pass
        self.update_displays()
    
    '''
        update_displays()

        Updates the displayed courses
    '''    
    def update_displays(self):
        self.courseList.clear()
        for courses in self.my_courses:
            item = [courses.display_string()]
            self.courseList.append(item)
            
        for i in range(self.num_years * SEMESTERS):
            list = self.semester_lists[i]
            list.clear()
            for course in self.app.get_semester_courses(i):
                list.append([course])
       
'''
    profile_maker

    The 'profile_maker' class allows a new user to create
    a profile in the system
'''
class profile_maker:
    
    '''
        __init__()

        Initializes the Glade file for use
    '''
    def __init__(self):
        self.gladefile = gladefile
    
    '''
        run()

        Creates and displays the screen where a new user
        can create a profile
    '''
    def run(self):
        self.wTree = gtk.glade.XML(self.gladefile, "profile_configurer") 
        
        self.dlg = self.wTree.get_widget("profile_configurer")

        dic = {"on_delete": self.delete_event}
        self.wTree.signal_autoconnect(dic)
        
        self.name = self.wTree.get_widget("name_entry")
        self.major = self.wTree.get_widget("major_box")
        self.minor = self.wTree.get_widget("minor_box")
            
        self.result = self.dlg.run()
        
        name = self.name.get_text()
        major = self.major.get_active()
        minor = self.minor.get_active()

        if(name == ''):
            name = 'Default Student'
        if(major < 0):
            major = 0
        if(minor < 0):
            minor = 0

        self.dlg.hide()
        print name, major, minor
        return self.result, name, major, minor

    '''
        delete_event()

        Closes the application if 'Cancel' is clicked
        during profile making
    '''
    def delete_event(self, widget, event, data=None):
        gtk.main_quit()

'''
    add_class_dialog

    The 'add_class_dialog' allows the student to view a
    particular course's relevant information
'''            
class add_class_dialog:
    
    '''
        __init__()

        Initializes the Glade file for use
    '''
    def __init__(self):
        self.gladefile = gladefile
    
    '''
        run()

        Creates and displays the screen where a particular
        course has all of its relevant information
    '''
    def run(self, text, semesters):
        self.wTree = gtk.glade.XML(self.gladefile, "add_course_dialog") 

        self.dlg = self.wTree.get_widget("add_course_dialog")

        self.semester_choice = self.wTree.get_widget("semester_select")
        # count the number of applicable semesters
        semester_ctr = 0
        for semester in semesters:
            self.semester_choice.append_text(SEASON_NAMES[semester])
            semester_ctr = semester_ctr + 1
        
        self.label = self.wTree.get_widget("cd_label")
        
        self.label.set_text(text)
        self.result = self.dlg.run()
        semester = self.semester_choice.get_active()
        
        # we have to increase the semester index for each applicable semester
        while(semester_ctr < 4):
            semester = semester + 1
            semester_ctr = semester_ctr + 1

        print semester
        self.dlg.destroy()
        return self.result, semester
    
'''
    edit_class_dialog

    The 'edit_class_dialog' allows the student to change a
    particular course's information such as its grade or 
    removing it from the plan
'''  
class edit_class_dialog:
    
    '''
        __init__()

        Initializes the Glade file for use
    '''
    def __init__(self):
        self.gladefile = gladefile
    
    '''
        run()

        Creates and displays the screen where the student can
        edit the grade of the course or remove the course from the plan
    '''
    def run(self, text):
        self.wTree = gtk.glade.XML(self.gladefile, "edit_course_dialogue") 

        self.dlg = self.wTree.get_widget("edit_course_dialogue")

        self.label = self.wTree.get_widget("edit_cd_label")
        
        self.label.set_text(text)
        self.result = self.dlg.run()
        self.dlg.destroy()
        return self.result
 
'''
    edit_grade_dialog

    The class 'edit_grade_dialog' allows the student to
    input a grade they received in a particular course
''' 
class edit_grade_dialog:
    
    '''
        __init__()

        Initializes the Glade file for use
    '''
    def __init__(self):
        self.gladefile = gladefile
    
    '''
        run()

        Creates and displays a screen where the student
        can change a particular course's grade
    '''
    def run(self, text):
        self.wTree = gtk.glade.XML(self.gladefile, "grade_change_dialog") 

        self.dlg = self.wTree.get_widget("grade_change_dialog")

        self.grade_choice = self.wTree.get_widget("grade_box")
        for grade in GRADES:
            self.grade_choice.append_text(grade)
        
        self.label = self.wTree.get_widget("current_grade")
        
        self.label.set_text(text)
        self.result = self.dlg.run()
        grade = self.grade_choice.get_active()
        self.dlg.destroy()
        return self.result, grade

'''
    cannot_remove_alert

    The class 'cannot_remove_alert' creates and displays
    an alert to the student when a particular course cannot
    be removed from their plan
'''
class cannot_remove_alert:
             
    '''
        __init__()

        Initializes the Glade file for use
    '''      
    def __init__(self):
        self.gladefile = gladefile
    
    '''
        run()

        Displays an alert to the student that the class cannot
        be removed from the plan
    '''
    def run(self):
        self.wTree = gtk.glade.XML(self.gladefile, "dialog1") 
        self.dlg = self.wTree.get_widget("dialog1")
        self.dlg.run()  
        self.dlg.destroy()
    
'''
    get_file

    The class 'get_file' lets the user choose a file,
    that he/she previously saved, for loading
'''
class get_file():
    
    '''
        __init__()

        Initializes the Glade file for use
    '''
    def __init__(self):
        self.gladefile = gladefile
        
    '''
        run()

        Allows the user to choose a file to load
    ''' 
    def run(self):
        self.wTree = gtk.glade.XML(self.gladefile, "file_chooser")
        self.dlg = self.wTree.get_widget("file_chooser")
        selected = ''
        response = self.dlg.run()
        selected =  self.dlg.get_filename()
        self.dlg.destroy()
        return response, selected  
        
if __name__ == "__main__":
	grad_gui()
	gtk.main()
